#include "SypEngine.h"

#ifdef CHECKMEM
#include "mmgr.h"
#endif


namespace Syp
{

	class GLExt
	{
	public:
		//////////////////VBO//////////////////////
		PFNGLBINDBUFFERARBPROC glBindBufferARB ;
		PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB ;
		PFNGLGENBUFFERSARBPROC glGenBuffersARB ;
		PFNGLBUFFERDATAARBPROC glBufferDataARB ;
		PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB ;
		PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements ;
		// GLSlang functions.
		PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB ;
		PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB ;
		PFNGLLINKPROGRAMARBPROC glLinkProgramARB ;
		PFNGLCOMPILESHADERARBPROC glCompileShaderARB ;
		PFNGLGETINFOLOGARBPROC glGetInfoLogARB ;
		PFNGLDELETEOBJECTARBPROC glDeleteObjectARB ;
		PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB ;
		PFNGLSHADERSOURCEARBPROC glShaderSourceARB ;
		PFNGLATTACHOBJECTARBPROC glAttachObjectARB ;
		PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB ;
		PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB ;
		PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
		PFNGLUNIFORM4FARBPROC glUniform4fARB ;
		PFNGLUNIFORM4FVARBPROC glUniform4fvARB;
		PFNGLUNIFORM1IARBPROC glUniform1iARB ;
		PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
		PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB ;
		PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB;
		PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
		PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
		PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
		PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
		PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
		PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
		PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
		PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
		PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
		PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
		//Compressed Textures
		PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2DARB;
	};

	static GLExt gl;
	/////////INIT CODE///////////////

	const char* Renderer::getExtensions()
	{
		return (char*)glGetString(GL_EXTENSIONS);
	}

	void getFrustum()
	{


	}

	void Renderer::release()
	{
		if(rnd)
		{
			ErrorLogger::getLogger()<<"Renderer properly released"<<std::endl;
			ErrorLogger::getLogger()<<"OpenGL Error : "<<glGetError()<<std::endl;		
			delete rnd;
			rnd = NULL;
		
		}
	}

	Renderer* Renderer::rnd = 0;

	Renderer::Renderer()
	{
		//defaults
		Width = 800;
		Height = 600;
		activeCamera = 0;

		currMode = PERSPECTIVE;
		currPass = 0;

		gl.glBindBufferARB = 0;
		gl.glDeleteBuffersARB = 0;
		gl.glGenBuffersARB = 0;
		gl.glBufferDataARB = 0;
		gl.glGetBufferParameterivARB = 0;
		gl.glDrawRangeElements = 0;

		currActiveLights = 0;
		boundTexture = 0;
		currBlendMode = NOBLEND;
	}

	void Renderer::disableColorWrites()
	{
		glDrawBuffer(GL_NONE);
	}
	void Renderer::disableColorReads()
	{
		glReadBuffer(GL_NONE);
	}

	void Renderer::bindFBO(FrameBufferObject* fbo)
	{		
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->getId());		
		//GLenum a = gl.glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
		glPushAttrib(GL_VIEWPORT_BIT);
		glViewport(0,0,fbo->getWidth(), fbo->getHeight());
	}

	void Renderer::readPixels(BufferObjectType type, PInt x, PInt y, PInt w, PInt h, float* data)
	{
		glReadPixels(x,y,w,h,type, GL_FLOAT, data);
	}


	void Renderer::unBindFBO()
	{
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		glPopAttrib();
	}

	Renderer::~Renderer()
	{
		SypEngine::getSypEngine().destroyMutex(TextureSubmissionMutex);
		//If there is an activeCamera, help the user to delete it, EDIT: DOnt do so
		//if(activeCamera)
		//{
		//	delete activeCamera;
		//	activeCamera = 0;
		//}

	}

	void Renderer::attachBuffer(FrameBufferObject* fbo, BufferObject* bo)
	{
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->getId());//Bind the Framebuffer we want to attach to
		gl.glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, bo->getId());//attach it
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	}

	void Renderer::removeTexture(TextureObj* to)
	{
		glDeleteTextures(1,&to->id);
	}

	void Renderer::setUpLight(Light* l)
	{
		const Point4& p = l->getPosition();
		float pos[] = {p.x,p.y,p.z,p.w};
		glEnable(GL_LIGHT0);
		glLightfv(GL_LIGHT0, GL_POSITION, pos);
		glLightfv(GL_LIGHT0, GL_AMBIENT, l->ambient);
		glLightfv(GL_LIGHT0, GL_SPECULAR, l->specular);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, l->diffuse);
		glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, l->exponent);
		glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, l->cutoff);
		glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, l->constantAttentuation);
		glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, l->linearAttentuation);
		glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, l->quadAttentuation);



	}

	void Renderer::setActiveCamera(Camera* cam)
	{
		assert(cam && "User attempted to pass in NULL value");
		activeCamera = cam;
		//Optimisation, we only do this when user changes camera
		setUpPerspective();
	}

	void Renderer::setScissorsRegion(int x, int y, int width, int height)
	{
		glScissor(x, y, width, height);
	}

	void Renderer::bindSubMaterial(SubMaterial& mat)
	{
		setUpBlendType(mat.btype);
		bindTexture(mat.diffuseMap);
		if(mat.lit)
		{
			glMaterialfv(GL_FRONT, GL_DIFFUSE, mat.diffuse);
			glMaterialfv(GL_FRONT, GL_AMBIENT, mat.ambient);
			glMaterialfv(GL_FRONT, GL_SPECULAR,mat.specular);
			glMaterialf(GL_FRONT,GL_SHININESS,mat.shininess);
		}
		else
		{
			//if it aint lit, only the ambient will be affected
			glMaterialfv(GL_FRONT, GL_AMBIENT, mat.ambient);
		}
		//GL Material stuff
	}

	void Renderer::bindMaterial(Material* mat)
	{
		boundMaterial = mat;
	}

	void Renderer::bindTexture(TextureObj* textureID)
	{
		if(boundTexture == textureID)
		{
			return;
		}
		if(textureID)
		{
			//bind texture once
			glBindTexture(GL_TEXTURE_2D,textureID->id);
		}
		else
		{
			glBindTexture(GL_TEXTURE_2D,0);
		}
		boundTexture = textureID;


	}

	void Renderer::resizeWindow(int width,int height)
	{
		if(rnd)
		{
			rnd->Width = width;
			rnd->Height = height;

			rnd->setUpViewport();
		}

	}

	FrameBufferObject* Renderer::generateFBOObj(PInt w, PInt h)
	{
		PInt fb;
		gl.glGenFramebuffersEXT(1, &fb);
		FrameBufferObject* fbo = new FrameBufferObject(fb,w, h);
		return fbo;

	}

	BufferObject* Renderer::generateBufferObj(BufferObjectType Type, PInt width, PInt height)
	{
		BufferObjectType type = Type;
		PInt rb = 0;
		gl.glGenRenderbuffersEXT(1, &rb);
		gl.glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
		gl.glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, type, width, height);
		BufferObject* bo = new BufferObject( rb, type, width, height);
		return bo;

	}

	void Renderer::deleteFrameBufferObject(FrameBufferObject* fbo)
	{
		PInt fb = fbo->getId();
		gl.glDeleteFramebuffersEXT(1, &fb);
	}

	void Renderer::generateTexObj(TextureObj* to)
	{
		glGenTextures(1,&to->id);
		glBindTexture(GL_TEXTURE_2D,to->id);
		//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
	}

	void Renderer::doAdmin()
	{//We will only upload 1 texture per frame max.
		SypEngine::lockMutex(TextureSubmissionMutex);
		std::list<TextureObj*>::iterator tsl = TextureSubmissionList.begin();
		if(tsl != TextureSubmissionList.end())
		{
			std::list<unsigned char*>::iterator data = TextureDataSubmission.begin();


			//---------------------------------------Textures-----------------------------------------
			TextureObj* toDebug = (*tsl);
			glBindTexture(GL_TEXTURE_2D, (*tsl)->id);

			if( (*tsl)->hasMipMaps )
			{
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
				//Gen in hardware
				glTexParameteri(GL_TEXTURE_2D,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
				
				//build mipmaps
				//gluBuild2DMipmaps(GL_TEXTURE_2D, (*tsl)->internalFormat, (*tsl)->width,(*tsl)->height, (*tsl)->format, GL_UNSIGNED_BYTE, (*data));
			}
			else
			{			//no mipmaps
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

				/*                     Test Code for checking if texture was compressed
				GLint compressed = 0;
				glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &compressed);
				glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT,
				&compressed);
				glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB,
				&compressed);	*/

			}
			if((*tsl)->format == COMPRESSED_RGB_DXT1 || (*tsl)->format == COMPRESSED_RGBA_DXT1 || (*tsl)->format == COMPRESSED_RGBA_DXT3 || (*tsl)->format == COMPRESSED_RGBA_DXT5)
			{
				gl.glCompressedTexImage2DARB( GL_TEXTURE_2D, 0, (*tsl)->internalFormat, (*tsl)->width, (*tsl)->height, 0, (*tsl)->dataSize, (*data));
			}
			else
			{
				glTexImage2D(GL_TEXTURE_2D, 0, (*tsl)->internalFormat, (*tsl)->width,(*tsl)->height, 0, (*tsl)->format, GL_UNSIGNED_BYTE, (*data));
			}
			//delete the image data
			glBindTexture(GL_TEXTURE_2D, this->boundTexture->id);
			delete[] (*data);
			(*tsl)->loaded = true;
			TextureSubmissionList.pop_front();
			TextureDataSubmission.pop_front();

		}
		SypEngine::unLockMutex(TextureSubmissionMutex);
		//---------------------------------------TexturesEnd-----------------------------------------
	}

	void Renderer::fillTexObj(TextureObj* to,unsigned char * data, bool now)
	{
		//we lock the lists
		if(now)
		{
			glBindTexture(GL_TEXTURE_2D, to->id);
			if( to->hasMipMaps )
			{
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
				//Gen mimaps in hardware
				glTexParameteri(GL_TEXTURE_2D,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);				
			}
			else
			{			//no mipmaps
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			}
			if(to->format == COMPRESSED_RGB_DXT1 || to->format == COMPRESSED_RGBA_DXT1 || to->format == COMPRESSED_RGBA_DXT3 || to->format == COMPRESSED_RGBA_DXT5)
			{
				gl.glCompressedTexImage2DARB( GL_TEXTURE_2D, 0, to->internalFormat, to->width, to->height, 0, to->dataSize, data);
			}
			else
			{
				glTexImage2D(GL_TEXTURE_2D, 0, to->internalFormat, to->width,to->height, 0, to->format, GL_UNSIGNED_BYTE, data);
			}
			//delete the image data
			if(boundTexture)
			{
				glBindTexture(GL_TEXTURE_2D, this->boundTexture->id);
			}
			delete[] data;
			to->loaded = true;

		}
		else
		{
			SypEngine::lockMutex(TextureSubmissionMutex);
			TextureSubmissionList.push_back(to);
			TextureDataSubmission.push_back(data);
			SypEngine::unLockMutex(TextureSubmissionMutex);
		}


	}

	void Renderer::setUpPerspective()
	{
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(activeCamera->getFOV(),activeCamera->getAspect(),activeCamera->getNearClip(),activeCamera->getFarClip());
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		//If we are changing to Perspective, we might as well apply the camera's transformation
		setUpCamera();
		currMode = PERSPECTIVE;
	}

	void Renderer::setUpCamera()
	{
		Point4 ac = activeCamera->getPosition();
		Quat temp = activeCamera->getOrientation();
		temp = temp.convertToAngleAxis();
		glRotatef(temp.w,temp.x,temp.y, temp.z);

		glTranslatef(-ac.x,-ac.y,-ac.z);
	/*	float invMat[16];
		//Math::InverseMatrix(activeCamera->getMatrix(), invMat);
		glLoadMatrixf(activeCamera->getMatrix());
		
		
		//gluLookAt(0.0f,0,400.0f, 0.0f,0,0.0f, 0,1.0f,0);



		//glOrtho(0.0f,Width,0.0f,Height,-1000.0f,1000.0f);*/
	}

	void Renderer::clearColorDepthBuffer()
	{
		//Clearing of screen
		// Clear Screen And Depth Buffer
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}

	void Renderer::clearColorBuffer()
	{
		glClear(GL_COLOR_BUFFER_BIT);
	}

	void Renderer::clearDepthBuffer()
	{
		glClear(GL_DEPTH_BUFFER_BIT);
	}


	BaseMesh* Renderer::getCurrentMesh()
	{
		return currentMesh;
	}

	MeshInstance* Renderer::getCurrentMI()
	{
		return currentMI;
	}

	Pass* Renderer::getCurrentPass()
	{
		return currPass;
	}

	void Renderer::setUniform4f(String& uniformName, PInt num, float* val)
	{
		int loc = gl.glGetUniformLocationARB( currPass->sp->id, uniformName.c_str() );
		gl.glUniform4fvARB(loc, num, val);
	}

	void Renderer::setUniformMatrix4f(String& uniformName, PInt num, float* val)
	{
		int loc = gl.glGetUniformLocationARB( currPass->sp->id, uniformName.c_str() );
		gl.glUniformMatrix4fvARB(loc, num, true,val);
	}

	void Renderer::bindMeshAttribBuffers(IndexedMesh* im, bool bindAttribData, bool bindAttribDatapb)
	{
		if(bindAttribData)
		{
			gl.glBindBufferARB( GL_ARRAY_BUFFER, im->attribID);
		}
		else if(bindAttribDatapb)
		{
			gl.glBindBufferARB( GL_ARRAY_BUFFER, im->attribPbID);
		}
	}

	void Renderer::setAttributef(String& attribName, PInt size, bool normalised, PInt stride, float* val)
	{
		int loc = gl.glGetAttribLocationARB( currPass->sp->id, attribName.c_str() );
		gl.glEnableVertexAttribArrayARB(loc);
		gl.glVertexAttribPointerARB(loc, size, GL_FLOAT, normalised, stride, val);
	}

	void Renderer::setAttributei(String& attribName, PInt size, bool normalised, PInt stride, PByte* val)
	{
		int loc = gl.glGetAttribLocationARB( currPass->sp->id, attribName.c_str() );
		gl.glEnableVertexAttribArrayARB(loc);
		gl.glVertexAttribPointerARB(loc, size, GL_UNSIGNED_BYTE, normalised, stride, val);
	}

	void Renderer::unSetAttribute(String& attribName)
	{
		int loc = gl.glGetAttribLocationARB( currPass->sp->id, attribName.c_str() );
		gl.glDisableVertexAttribArrayARB(loc);
	}
	void Renderer::draw(MeshInstance* i, PInt drawCall,Pass* p)
	{
		if( !i->visible )
		{//if it's not visible, exit
			return;
		}
		currentMI = i;
		currentMesh = i->getMesh();
		currDrawCall = drawCall;
		PInt prevSPID = 0;
		if(currPass && currPass->sp)
		{
			prevSPID = currPass->sp->id;
		}
		currPass = p;


		if( gfxcard.VertexShaders && gfxcard.PixelShaders)
		{
			if(p->sp)
			{
				bool dontRebind = (prevSPID == p->sp->id);
				if(!dontRebind)
				{
					gl.glUseProgramObjectARB(p->sp->id);
				}
			}
			else
			{
				gl.glUseProgramObjectARB(0);
			}
		}

		p->preDraw();


		if(i->mode != currMode)
		{
			if(i->mode == ORTHO)
			{
				setUpOrtho();
			}
			else
			{
				setUpPerspective();
			}
		}

		//bind Material
		bindMaterial(i->material);
		//Bind VBOs and setup Vertex Pointers
		setUpVertexPointers(currentMesh);
		//test only once if STATIC
		glPushMatrix();
		const Point4& po = i->getPosition();
		Quat qu = i->getOrientation();
		AngleAxis aa = qu.convertToAngleAxis();
		glTranslatef(po.x,po.y,po.z);
		glRotatef(aa.w,aa.x,aa.y,aa.z);

		//Moved up above predraw to allow setting up of shader uniforms/att
		//if( gfxcard.VertexShaders && gfxcard.PixelShaders)
		//{
		//	if(p->sp)
		//	{
		//		gl.glUseProgramObjectARB(p->sp->id);
		//	}
		//	else
		//	{
		//		gl.glUseProgramObjectARB(0);
		//	}
		//}
		currentMesh->draw();


		glPopMatrix();

		unSetVertexPointers();
		++i;
		p->postDraw();

		// Everything Went OK
	}

	void Renderer::swapBuffers()
	{
		glfwSwapBuffers();
	}

	PInt Renderer::calcVBOsize(BaseMesh* m)
	{
		PInt size = 0;
		switch(m->vertType)
		{
		case VNT:
			//if there is a texture, 3 vertex + 3 normal + 2uv
			size = m->numOfVertices * 8 * sizeof(float);
			break;
		case VT:
			size = m->numOfVertices * 5 * sizeof(float);
			break;
		case VC3:
			size = m->numOfVertices * 6 * sizeof(float);
			break;
		case VC4:
			size = m->numOfVertices * 7 * sizeof(float);
			break;
		case VC3T:
			size = m->numOfVertices * 8 * sizeof(float);
			break;
		case VC4T:
			size = m->numOfVertices * 9 * sizeof(float);
			break;
		case VN:
			size = m->numOfVertices * 6 * sizeof(float);
			break;
		default:
			assert(false && "Invalid Vertex Format specified.");
			break;
		}
		return size;
	}



	void Renderer::addMesh(IndexedMesh* m)
	{
		//Generate 2 buffers, 1 for data, 1 for indices
		/*if(m->type == STATIC)
		{*/
		gl.glGenBuffersARB(1, &m->dataID);
		/*gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
		gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB, calcVBOsize(m),&m->data[0],m->type);*/

		gl.glGenBuffersARB(1, &m->indexID);
		/*gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m->indexID);
		gl.glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m->index.size() * sizeof(PShort),&m->index[0],m->type);*/
		gl.glGenBuffersARB(1, &m->attribID);
		gl.glGenBuffersARB(1, &m->attribPbID);
		// Since we are done loading lets unbind everything to be safe.
		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);


		m->calcStride();
	}


	void Renderer::updateMesh(BaseMesh* m)
	{
		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
		//invalidate data
		gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,0, 0, m->type);
		if(m->numOfVertices)
		{
			gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,calcVBOsize(m),&m->data[0],m->type);
		}

		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		m->calcStride();
	}

	void Renderer::updateIndices(IndexedMesh *m)
	{
		gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m->indexID);
		gl.glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m->index.size() * sizeof(PShort), 0, m->type);
		gl.glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m->index.size() * sizeof(PShort),&m->index[0],m->type);

		gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->attribID);
		//invalidate data
		gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,0, 0, m->type);
		if(m->attribData.size())
		{
			gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,m->attribData.size() * sizeof(float), &m->attribData[0],m->type);
		}

		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->attribPbID);
		//invalidate data
		gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,0, 0, m->type);
		if( m->attribDatapb.size() )
		{
			gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,m->attribDatapb.size() * sizeof(PByte), &m->attribDatapb[0],m->type);
		}
		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

		m->calcStride();
	}


	void Renderer::removeMeshFromVRAM(NIndexedMesh* m)
	{
		gl.glDeleteBuffersARB(1, &m->dataID);
	}

	void Renderer::removeMeshFromVRAM(IndexedMesh* m)
	{
		gl.glDeleteBuffersARB(1, &m->dataID);

		gl.glDeleteBuffersARB(1, &m->indexID);
	}

	void Renderer::addMesh(NIndexedMesh* m)
	{
		//Generate 1 buffers, 1 for data
		gl.glGenBuffersARB(1, &m->dataID);
		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
		if(m->numOfVertices)
		{
			gl.glBufferDataARB(GL_ARRAY_BUFFER_ARB,calcVBOsize(m),&m->data[0],m->type);
		}

		// Since we are done loading lets unbind everything to be safe.
		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
	}


	void Renderer::unSetVertexPointers()
	{
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_NORMAL_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_COLOR_ARRAY);

		gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

	}

	void Renderer::setUpVertexPointers(BaseMesh* m)
	{
		switch(m->vertType)
		{
		case VNT:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_NORMAL_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glEnable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glNormalPointer(GL_FLOAT,m->stride,(char*)(0 + 3*sizeof(float)));
			glTexCoordPointer(2,GL_FLOAT,m->stride,(char*)(0 + 6*sizeof(float)));
			break;
		case VT:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glDisable(GL_LIGHTING);  //No normals so disable lighting

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glTexCoordPointer(2,GL_FLOAT,m->stride,(char*)0 + (3*sizeof(float)) );
			break;
		case VN:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_NORMAL_ARRAY);
			glEnable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glNormalPointer(GL_FLOAT,m->stride,(char*)(0 + 3*sizeof(float)));
			break;
		case VC3:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);
			glDisable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glColorPointer(3,GL_FLOAT,m->stride,(char*)(0 + 3 * sizeof(float)));
			break;
		case VC4:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);
			glDisable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glColorPointer(4,GL_FLOAT,m->stride,(char*)(0 + 3 * sizeof(float)));
			break;
		case VC3T:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glDisable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glColorPointer(3,GL_FLOAT,m->stride,(char*)(0 + 3 * sizeof(float)));
			glTexCoordPointer(2,GL_FLOAT,m->stride,(char*)0 + (6*sizeof(float)) );
			break;
		case VC4T:
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glDisable(GL_LIGHTING);

			gl.glBindBufferARB(GL_ARRAY_BUFFER_ARB, m->dataID);
			glVertexPointer(3,GL_FLOAT,m->stride,0);
			glColorPointer(4,GL_FLOAT,m->stride,(char*)(0 + 3 * sizeof(float)));
			glTexCoordPointer(2,GL_FLOAT,m->stride,(char*)0 + (7*sizeof(float)) );
			break;
		}

	}

	void Renderer::setUpBlendType(BlendType b)
	{
		if(this->currBlendMode == b)
		{
			return;
		}
		switch(b)
		{
		case NOBLEND:
			glDisable(GL_ALPHA_TEST);
			glDisable(GL_BLEND);
			break;
		case ALPHA:
			glEnable(GL_ALPHA_TEST);
			glDisable(GL_BLEND);
			break;
		case BLEND:
			glEnable(GL_ALPHA_TEST);
			glEnable(GL_BLEND);
			break;
		}
		currBlendMode = b;
	}

	void Renderer::drawIndexed(IndexedMesh* m)
	{
		////Ensure that the mesh has similar number of subMeshes as currently bound Material's subMaterials
		//assert(m->drawCalls.size() == boundMaterial->subMaterials.size() && "The Mesh does not have equivalent number of drawCalls/SubMeshes as the currently bound Material");
		//test only once if STATIC
		polyDrawn += m->drawCalls[currDrawCall].count/3;
		gl.glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m->indexID);
		bindSubMaterial(boundMaterial->subMaterials[ m->drawCalls[ currDrawCall ].materialID ]);
		gl.glDrawRangeElements(m->format,m->drawCalls[currDrawCall].smallest,m->drawCalls[currDrawCall].largest, m->drawCalls[currDrawCall].count,GL_UNSIGNED_SHORT, (char*)(0 + m->drawCalls[currDrawCall].offset * sizeof(PShort)) );


		//Morph mesh according to what the instance wants it to be
		/*
		Problem with this method is that cpu intensive work of transforming mesh has to be done before each draw call meaning parrallelism is broken. Another way could be to make copies of all transformed meshes and then submit for rendering. But could be overkill and use up insane amounts of memory in a RTS. Then again, you wouldnt use skeletal animation in a RTS.

		This problem is also made obsolete if using vertex programs to do the skinning.Since the gfx card will be doing most of the work.
		*/

	}

	void Renderer::drawNIndexed(NIndexedMesh* m)
	{
		bindSubMaterial(boundMaterial->subMaterials[ m->drawCalls[ currDrawCall ].materialID ]);
		glDrawArrays(m->format, 0,m->numOfVertices);
	}

	void Renderer::setUpOrtho()
	{
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0.0f,Width,0.0f,Height,activeCamera->getNearClip(),activeCamera->getFarClip());
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		setUpCamera();
		currMode = ORTHO;
	}


	void Renderer::setUpViewport()
	{
		if(Height==0)
		{
			Height=1;
		}
		glViewport(0,0,Width,Height);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	}

	bool Renderer::checkExtension(String item)
	{
		//If extensions have not been recieved from gfx card
		if(extensions == "")
		{
			extensions = getExtensions();
		}
		std::istringstream parser;
		String temp;

		parser.str(extensions);

		while(!parser.eof())
		{
			//read in an extension
			parser>>temp;
			if(temp == item)
			{//if extension matches
				return true;
			}//else carry on searching
		}
		//else return false
		return false;
	}

	void Renderer::setGlobalAmbience(const Point4& globalAmb)
	{
		float global_ambient[] = { globalAmb.x,globalAmb.y,globalAmb.z,globalAmb.w};
		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

	}

	void Renderer::setUpLights(PInt numLights)
	{
		////User wants to reduce lights
		//if(currActiveLights > numLights)
		//{
		//	PInt i = GL_LIGHT0 + currActiveLights;
		//	for(PInt j=currActiveLights;j>numLights;--j)
		//	{
		//		glDisable(i);
		//		--i;
		//	}
		//
		//}
		//else
		//{
		//	//This prevents us from enabling more lights then needed
		//	PInt i = GL_LIGHT0 + currActiveLights;
		//	for(PInt j=currActiveLights;j<numLights;++j)
		//	{
		//		glEnable(i);
		//		++i;
		//	}
		//}
		currActiveLights = numLights;




	}

	void Renderer::initRenderer(int width, int height)
	{
		if(!rnd)
		{
			rnd = new Renderer();
			rnd->Width = width;
			rnd->Height = height;

			rnd->TextureSubmissionMutex = SypEngine::getSypEngine().createMutex();

			rnd->initGL();

			rnd->setUpViewport();

			ErrorLogger::getLogger()<<"Resolution Requested : "<<width<<"X"<<height<<std::endl;

			ErrorLogger::getLogger()<<"Manufacturer :"<<glGetString(GL_VENDOR)<<std::endl;
			ErrorLogger::getLogger()<<"Gfx Card :"<<glGetString(GL_RENDERER)<<std::endl;
			ErrorLogger::getLogger()<<"Version :"<<glGetString(GL_VERSION)<<std::endl<<std::endl;

			//Extensions
			rnd->extensions = rnd->getExtensions();

			//Dump extensions to logfile
			ErrorLogger::getLogger()<<"Extensions supported : "<<std::endl;
			ErrorLogger::getLogger()<<rnd->extensions<<std::endl<<std::endl;

			//Check CubeMaps support
			if(rnd->checkExtension("GL_ARB_texture_cube_map"))
			{
				ErrorLogger::getLogger()<<"Cubemaps support found.\n";
				rnd->gfxcard.CubeMaps = true;
			}
			else
			{
				ErrorLogger::getLogger()<<"Cubemaps support NOT found.\n";
				rnd->gfxcard.CubeMaps = false;
			}

			//Check compressed textures support
			if(rnd->checkExtension("GL_EXT_texture_compression_s3tc"))
			{
				gl.glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)glfwGetProcAddress("glCompressedTexImage2DARB");
				if(gl.glCompressedTexImage2DARB)
				{
					ErrorLogger::getLogger()<<"Compressed Textures supported.\n";
					rnd->gfxcard.CompressedTextures = true;
				}
				else
				{
					ErrorLogger::getLogger()<<"Compressed textures not supported. Game might not run if uncompressed textures are not provided\n";
				}
			
			}

			//Check VBO support
			if(rnd->checkExtension("GL_ARB_vertex_buffer_object"))
			{
				//get entry points for extension functions
				gl.glBindBufferARB  =
					(PFNGLBINDBUFFERARBPROC)glfwGetProcAddress("glBindBufferARB");
				gl.glDeleteBuffersARB =
					(PFNGLDELETEBUFFERSARBPROC)glfwGetProcAddress("glDeleteBuffersARB");
				gl.glGenBuffersARB    =
					(PFNGLGENBUFFERSARBPROC)glfwGetProcAddress("glGenBuffersARB");
				gl.glBufferDataARB    =
					(PFNGLBUFFERDATAARBPROC)glfwGetProcAddress("glBufferDataARB");
				gl.glGetBufferParameterivARB =
					(PFNGLGETBUFFERPARAMETERIVARBPROC)glfwGetProcAddress("glGetBufferParameterivARB");
				gl.glDrawRangeElements =
					(PFNGLDRAWRANGEELEMENTSPROC)glfwGetProcAddress("glDrawRangeElements");

				//check whether we successfully obtained the entry points
				assert(gl.glBindBufferARB && gl.glDeleteBuffersARB && gl.glGenBuffersARB && gl.glBufferDataARB &&gl.glGetBufferParameterivARB&&gl.glDrawRangeElements && "Error getting one or more of the ARB vertex buffer object functions! ");

				//VBO is supported, do initialisation here



				ErrorLogger::getLogger()<<"VBO support found!"<<std::endl;
			}
			else
			{
				//VBO's not supported switch back to Display Lists
				ErrorLogger::getLogger()<<"Error getting one or more of the ARB vertex buffer object functions! Please update your graphic card drivers by visiting your graphic card manufacturer's website."<<std::endl;

			}
			//Check Shader Support
			if(rnd->checkExtension("GL_ARB_shading_language_100") && rnd->checkExtension("GL_ARB_shader_objects"))
			{
				gl.glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)glfwGetProcAddress("glCreateProgramObjectARB");
				gl.glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)glfwGetProcAddress("glCreateShaderObjectARB");
				gl.glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)glfwGetProcAddress("glCompileShaderARB");
				gl.glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)glfwGetProcAddress("glLinkProgramARB");
				gl.glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)glfwGetProcAddress("glGetInfoLogARB");
				gl.glDeleteObjectARB  = (PFNGLDELETEOBJECTARBPROC)glfwGetProcAddress("glDeleteObjectARB");
				gl.glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)glfwGetProcAddress("glUseProgramObjectARB");
				gl.glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)glfwGetProcAddress("glShaderSourceARB");
				gl.glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)glfwGetProcAddress("glAttachObjectARB");
				gl.glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)glfwGetProcAddress("glGetObjectParameterivARB");
				gl.glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)glfwGetProcAddress("glGetUniformLocationARB");
				gl.glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)glfwGetProcAddress("glGetAttribLocationARB");
				gl.glUniform4fARB = (PFNGLUNIFORM4FARBPROC)glfwGetProcAddress("glUniform4fARB");
				gl.glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)glfwGetProcAddress("glUniform4fvARB");
				gl.glUniform1iARB = (PFNGLUNIFORM1IARBPROC)glfwGetProcAddress("glUniform1iARB");
				gl.glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)glfwGetProcAddress("glVertexAttribPointerARB");
				gl.glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)glfwGetProcAddress("glEnableVertexAttribArrayARB");
				gl.glUniformMatrix4fvARB = 	(PFNGLUNIFORMMATRIX4FVARBPROC)glfwGetProcAddress("glUniformMatrix4fvARB");
				gl.glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)glfwGetProcAddress("glDisableVertexAttribArrayARB");
				//Check that we got all the required function pointers

				if(!gl.glCreateProgramObjectARB || !gl.glCreateShaderObjectARB ||  !gl.glCompileShaderARB ||
					!gl.glLinkProgramARB || !gl.glGetInfoLogARB || !gl.glDeleteObjectARB || !gl.glUseProgramObjectARB ||
					!gl.glShaderSourceARB || !gl.glAttachObjectARB || !gl.glGetObjectParameterivARB ||
					!gl.glGetUniformLocationARB || !gl.glUniform4fARB || !gl.glUniform1iARB || !gl.glUniform4fvARB ||
					!gl.glGetAttribLocationARB || !gl.glVertexAttribPointerARB || !gl.glEnableVertexAttribArrayARB	||
					!gl.glUniformMatrix4fvARB || !gl.glDisableVertexAttribArrayARB )
				{
					ErrorLogger::getLogger()<<"Error getting one of the required Shader function pointers. Please update your graphics card drivers and try again."<<std::endl;
					rnd->gfxcard.VertexShaders = false;
					rnd->gfxcard.PixelShaders = false;

				}
				else
				{
					ErrorLogger::getLogger()<<"Shader support found!"<<std::endl;
					rnd->gfxcard.VertexShaders = true;
					rnd->gfxcard.PixelShaders = true;
				}
			}
			else
			{//Shaders not supported
				ErrorLogger::getLogger()<<"Shaders not supported on your system. If you are using a graphics card/newer than Geforce:FX or Radeon 9xxx series, please update your video card drivers."<<std::endl;
				rnd->gfxcard.VertexShaders = false;
				rnd->gfxcard.PixelShaders = false;

			}
			//Check FBO support
			if(rnd->checkExtension("GL_EXT_framebuffer_object"))
			{
				gl.glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)glfwGetProcAddress("glGenFramebuffersEXT");
				gl.glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)glfwGetProcAddress("glDeleteFramebuffersEXT");
				gl.glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)glfwGetProcAddress("glBindFramebufferEXT");
				gl.glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)glfwGetProcAddress("glGenRenderbuffersEXT");
				gl.glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)glfwGetProcAddress("glBindRenderbufferEXT"); 
				gl.glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)glfwGetProcAddress("glRenderbufferStorageEXT"); 
				gl.glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)glfwGetProcAddress("glFramebufferRenderbufferEXT"); 
				gl.glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)glfwGetProcAddress("glCheckFramebufferStatusEXT"); 
				gl.glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)glfwGetProcAddress("glFramebufferTexture2DEXT"); 
				ErrorLogger::getLogger()<<"FBO support found!\n";
				rnd->gfxcard.FBO = true;
			}
			else
			{
				ErrorLogger::getLogger()<<"No FBO support found...\n";
			}
			if(rnd->checkExtension("GL_ARB_point_sprite") )
			{
				rnd->gfxcard.PointSprites = true;
			}
		}
	}

	const HardwareCapabilities& Renderer::getHardwareCpbRef()
	{
		return gfxcard;
	}

	void Renderer::enablePointSprites()
	{
		glEnable(GL_POINT_SPRITE);
		glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
	}

	void Renderer::disablePointSprites()
	{
		glDisable(GL_POINT_SPRITE);
		glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE);
	}

	void Renderer::setPointSpritesSize(float size)
	{
		glPointSize(size);
	}
	void Renderer::setClearColor(Color3f& c,float alpha)
	{
		glClearColor(c.r, c.g, c.b, alpha);//clear black color
	}

	void Renderer::enableDepthTest()
	{
		glEnable(GL_DEPTH_TEST);
	}

	void Renderer::disableDepthTest()
	{
		glDisable(GL_DEPTH_TEST);
	}

	void Renderer::initGL()										// All Setup For OpenGL Goes Here
	{
		glClearColor(0, 0, 0, 1.0f);//clear black color

		glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
		//Back face culling
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);
		//Z-Bufering
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LESS);

		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		//glBlendFunc(GL_ONE,GL_ONE);
		glEnable(GL_TEXTURE_2D);

		//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
		glEnable(GL_LIGHTING);
		//glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);

		glShadeModel(GL_SMOOTH) ;
		//float fogColor[]={0.4f,0.4f,0.4f,1.0f};
		//fog

		//glFogi(GL_FOG_MODE, GL_LINEAR);
		//glFogfv(GL_FOG_COLOR, fogColor);
		//glFogf(GL_FOG_DENSITY, 1.0f);
		//glHint(GL_FOG_HINT, GL_NICEST);
		//glFogf(GL_FOG_START, 10.0f);					// Fog Start Depth
		//glFogf(GL_FOG_END, 3002.0f);					// Fog End Depth
		//glEnable(GL_FOG);


		glAlphaFunc(GL_GREATER, 0.0f);

		/*--------------------------------------------------------------------------*/
		/*--------------------------------------------------------------------------*/
		/*--------------------------------------------------------------------------*/
		/*--------------------------------------------------------------------------/**/



	}

	//void Renderer::doTextureSort()
	//{
	//	std::list<BaseMesh*>::iterator i = MeshManager::getMeshManager().Meshes.begin();
	//	std::list<BaseMesh*>::iterator end = MeshManager::getMeshManager().Meshes.end();
	//
	//	std::list<MeshInstance*>::iterator j;
	//	std::list<MeshInstance*>::iterator jend;
	//
	//	//We clear the RenderQue and add sorted by Mesh.
	//	Instances.clear();
	//	//for every mesh
	//	while (i != end)
	//	{
	//		jend = (*i)->instances.end();
	//		for(j = (*i)->instances.begin();j != jend;++j)
	//		{
	//			//we push back the instance in this mesh
	//			Instances.push_back( (*j) );
	//		}
	//		++i;
	//	}
	//
	//}


	void Renderer::compilePixelShader(PixelShader* ps)
	{
		compileShader(ps);
	}

	void Renderer::deleteShader(Shader* s)
	{
		gl.glDeleteObjectARB(s->id);
	}

	void Renderer::deleteShaderProgram(ShaderProgram* sp)
	{
		gl.glDeleteObjectARB(sp->id);
	}

	void Renderer::compileVertexShader(VertexShader* vs)
	{
		compileShader(vs);
	}

	void Renderer::compileShader(Shader* vs)
	{
		const char* s = vs->source.c_str();
		const char** ss = &s;
		gl.glShaderSourceARB(vs->id, 1, ss, 0);
		gl.glCompileShaderARB(vs->id);

		char log[1000];
		int chWrt;
		gl.glGetInfoLogARB(vs->id,1000, &chWrt, log);
		ErrorLogger::getLogger()<<"Compile Log for shader "<<vs->getFileName()<<" "<<chWrt<<" bytes long.\n";
		ErrorLogger::getLogger()<<log<<std::endl;
		vs->compiled = true;

	}

	PInt Renderer::generatePixelShader()
	{
		return gl.glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
	}

	PInt Renderer::generateVertexShader()
	{
		return gl.glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
	}

	PInt Renderer::generateShaderProgram()
	{
		return gl.glCreateProgramObjectARB();
	}

	void Renderer::attachTexture(FrameBufferObject* fbo, TextureObj* tex)
	{
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->getId());	
		gl.glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex->id, 0);
		#ifdef _DEBUG
		ErrorLogger::getLogger()<<"FBO Status after attachTexture(36053 is success) "<<gl.glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)<<"\n";
		#endif
		gl.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);	
	}

	void Renderer::attachShaderToProgram(Shader* s,ShaderProgram* sp)
	{
		gl.glAttachObjectARB(sp->id,s->id);
	}

	void Renderer::linkShaders(ShaderProgram* sp)
	{
		gl.glLinkProgramARB(sp->id);
		char log[1000];
		int chWrt;
		gl.glGetInfoLogARB(sp->id,1000, &chWrt, log);
		ErrorLogger::getLogger()<<"Compile Log for shader "<<sp->getFileName()<<" "<<chWrt<<" bytes long.\n";
		ErrorLogger::getLogger()<<log<<std::endl;

	}
	PInt Renderer::getNumPolyDrawn()
	{
		return polyDrawn;
	}
	void Renderer::updatePolyDrawn()
	{
		polyDrawn = polyCount;
		polyCount = 0;
	}
}
